from skillchallenge.models import *
import EventEngine
import CodeEngine
import LocationEngine
import ItemEngine
import ChatEngine
import SkillChallengeEngine
from django.db.models import Q

class __Game__:    
    def __init__(self, char=None):
        if Tick.objects.count() == 0:
            Tick.objects.create(tick = 1)
        if Config.objects.count() == 0:
            self.config = Config.objects.create()
        else:
            self.config = Config.objects.get(id=1)
        self.char = char
        
    code_engine = CodeEngine.CodeEngine()
    event_engine = EventEngine.EventEngine()
    location_engine = LocationEngine.LocationEngine()
    item_engine = ItemEngine.ItemEngine()
    chat_engine = ChatEngine.ChatEngine()
    
    def update_tick(self):
        self.refresh_char()
#        current = Tick.objects.latest()
#        current = Tick.objects.filter(tick=current.tick).order_by('datetime')[0]
#        from datetime import datetime
#        diff = (datetime.now() - current.datetime).seconds
#        for i in range(int(diff/self.config.seconds_per_tick)):
#            self.tick()
    
    def tick(self):
        tick = 1
        previous = Tick.objects.latest()
        if previous:
            tick = previous.tick + 1
            
        for char in Character.objects.all():
            char.action_points = self.config.action_points_per_tick  
            char.save()  
        
        now = Tick.objects.create(tick = tick)
        availables = self.event_engine.not_fired()
        for failed in availables.filter(scheduled = True).filter(schedule_end__lt = Tick.objects.latest()):
            self.event_engine.fire_fail(failed)
        
        to_fire = self.__preconditions_filter__(availables.filter(failed = False).filter(player_will = False))
                
        for event in to_fire:
            self.fire(event)
            
        for event in availables.filter(current_offline = True):
            event.current_offline = False
            event.save()
        
        for event in self.__preconditions_filter__(availables.filter(failed = False).filter(player_will = True).filter(online = False)):
            event.current_offline = True
            event.save()
    
    def messages(self):
        return Message.objects.all()
    
    def __execute_actions__(self, event, char = None, debug = False):
        if debug: print 'executing >>> ' + str(event) + ' >>> executer : ' + str(char)
        for action in event.actions.all():
            result = self.code_engine.execute(action, char, debug)
            if type(result) == Event:
                fired = False
                for event in self.__preconditions_filter__([result], debug):
                    self.fire(event, debug)
                    fired = True
                if not fired:
                    self.event_engine.fire_fail(result)
            
    def player_fire(self, event, char, debug = False):
        if char:
            char = Character.objects.get(id=char.id)
        
        self.online_event_stack.append(event)
        self.__execute_actions__(event, char, debug)            
        onlines = self.__get_onlines__(debug)        
        self.event_engine.player_fire(event)
        self.__check_online_events__(onlines, debug)
        self.online_event_stack.remove(event)
        
        if char:
            char = Character.objects.get(id=char.id)
            char.action_points = char.action_points - event.cost
            char.save()
                    
    def fire(self, event, debug = False):
        self.online_event_stack.append(event)
        self.__execute_actions__(event, debug)            
        onlines = self.__get_onlines__(debug)
        self.event_engine.fire(event)
        self.__check_online_events__(onlines, debug)
        self.online_event_stack.remove(event)
    
    online_event_stack = []
       
    def __get_onlines__(self, debug = False):
        onlines = []
        
        if debug: 
            print 'event stack >>> ' + str(self.online_event_stack)
        
        for event in self.event_engine.not_fired().filter(player_will=False).filter(online = True):
            onlines.append(event)
        
        for event in self.online_event_stack: 
            if event in onlines:
                onlines.remove(event)
        return onlines
    
    def __check_online_events__(self, onlines, debug = False):
        if debug: print 'checking online events >>> ' + str(onlines)
        to_fire = self.__preconditions_filter__(onlines, debug)
        
        for event in to_fire:
            self.online_event_stack.append(event)
        
        for event in to_fire:
            self.fire(event)            
            
        for event in to_fire:
            self.online_event_stack.remove(event)
    
    def player_available(self, debug_online=False, debug_offline=False ):
        availables = self.__preconditions_filter__(self.event_engine.player_available().filter(current_offline = True), debug_offline)
        availables.extend(self.__preconditions_filter__(self.event_engine.player_available().filter(online = True), debug_online))
        if self.chat_engine.is_chatting():
            availables = [a for a in availables if a.chatting] 
        
        return availables 
    
    def affordable(self, availables):
        if self.char:
            return [a for a in availables if a.cost <= self.char.action_points]
    
    def expensive(self, availables):
        if self.char:
            return [a for a in availables if a.cost > self.char.action_points]
    
    def __preconditions_filter__(self, events, debug =False):
        result = []
        for event in events:
            if debug: print 'to test : ' + str(event) + ' >> ' + str(event.preconditions.all())
            if self.code_engine.preconditions_met(event.preconditions.all(), debug):
                result.append(event)
        return result
    
    def set_random(self, random):
        SkillChallengeEngine.SkillChallengeEngine.random = random
        
    def quest_set(self):
        if self.char:
            if self.char.questmodel_set.filter(success=False).filter(failed=False).count() > 0:
                return self.char.questmodel_set.filter(success=False).filter(failed=False)[0]
        return None
    
    def completed_quests(self):
        if self.char:
            q = Q(success=True)
            if self.char.questmodel_set.filter(q).count() > 0:
                return self.char.questmodel_set.filter(q)
    
    def failed_quests(self):
        if self.char:
            q = Q(failed=True)
            if self.char.questmodel_set.filter(q).count() > 0:
                return self.char.questmodel_set.filter(q)
    
    def score(self):
        
        if self.char:
            return self.char.score
    
    def action_points(self):
        if self.char:
            return self.char.action_points
    
    def refresh_char(self):
        if self.char:
            self.char = Character.objects.get(id=self.char.id)